using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Threading;
using System.Windows.Forms;

namespace HslControls
{
	/// <summary>
	/// 仪表盘控件对象
	/// </summary>
	[Description("旧的仪表盘控件，外观像一把扇子，支持设置范围，指针颜色，报警区域")]
	public class HslGauge : UserControl
	{
		private Color color_gauge_border = Color.DimGray;

		private Brush pen_gauge_mark = new SolidBrush(Color.DimGray);

		private Brush foreBrush = new SolidBrush(Color.DodgerBlue);

		private Color color_gauge_pointer = Color.Tomato;

		private Brush brush_gauge_pointer = null;

		private float value_start = 0f;

		private float value_max = 100f;

		private float value_current = 0f;

		private float value_alarm_max = 80f;

		private float value_alarm_min = 20f;

		private Color color_gauge_alarm = Color.OrangeRed;

		private Pen pen_gauge_alarm = null;

		private int m_version = 0;

		private float value_paint = 0f;

		private object hybirdLock;

		private Action m_UpdateAction;

		private int segment_count = 10;

		private StringFormat sf = null;

		private string value_unit_text = string.Empty;

		private bool text_under_pointer = true;

		private bool isBigSemiCircle = false;

		private int pointerSize = 5;

		private string customerCalibration = string.Empty;

		private bool isTextInfoRenderBlow = false;

		/// <summary> 
		/// 必需的设计器变量。
		/// </summary>
		private IContainer components = null;

		/// <summary>
		/// 获取或设置控件的背景色
		/// </summary>
		[Browsable(true)]
		[Description("获取或设置控件的背景色")]
		[Category("HslControls")]
		[DefaultValue(typeof(Color), "Transparent")]
		[EditorBrowsable(EditorBrowsableState.Always)]
		public override Color BackColor
		{
			get
			{
				return base.BackColor;
			}
			set
			{
				base.BackColor = value;
			}
		}

		/// <summary>
		/// 获取或设置仪表盘的背景色
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置仪表盘的背景色")]
		[DefaultValue(typeof(Color), "DimGray")]
		public Color GaugeBorder
		{
			get
			{
				return color_gauge_border;
			}
			set
			{
				color_gauge_border = value;
				pen_gauge_mark.Dispose();
				pen_gauge_mark = new SolidBrush(value);
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置指针的颜色
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置仪表盘指针的颜色")]
		[DefaultValue(typeof(Color), "Tomato")]
		public Color PointerColor
		{
			get
			{
				return color_gauge_pointer;
			}
			set
			{
				brush_gauge_pointer?.Dispose();
				brush_gauge_pointer = new SolidBrush(value);
				color_gauge_pointer = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置数值的起始值，默认为0
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置数值的起始值，默认为0")]
		[DefaultValue(0f)]
		public float ValueStart
		{
			get
			{
				if (value_max <= value_start)
				{
					return value_start + 1f;
				}
				return value_start;
			}
			set
			{
				value_start = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置数值的最大值，默认为100
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置数值的最大值，默认为100")]
		[DefaultValue(100f)]
		public float ValueMax
		{
			get
			{
				if (value_max <= value_start)
				{
					return value_start + 1f;
				}
				return value_max;
			}
			set
			{
				value_max = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置数值的当前值，应该处于最小值和最大值之间
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置数值的当前值，默认为0")]
		[DefaultValue(0f)]
		public float Value
		{
			get
			{
				return value_current;
			}
			set
			{
				if (value != value_current)
				{
					value_current = value;
					int version = Interlocked.Increment(ref m_version);
					ThreadPool.QueueUserWorkItem(ThreadPoolUpdateProgress, version);
				}
			}
		}

		/// <summary>
		/// 获取或设置数值的上限报警值，设置为超过最大值则无上限报警
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置数值的上限报警值，设置为超过最大值则无上限报警，默认为80")]
		[DefaultValue(80f)]
		public float ValueAlarmMax
		{
			get
			{
				return value_alarm_max;
			}
			set
			{
				if (ValueStart <= value)
				{
					value_alarm_max = value;
					Invalidate();
				}
			}
		}

		/// <summary>
		/// 获取或设置数值的下限报警值，设置为超过最大值则无上限报警
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置数值的下限报警值，设置为小于最小值则无下限报警，默认为20")]
		[DefaultValue(20f)]
		public float ValueAlarmMin
		{
			get
			{
				return value_alarm_min;
			}
			set
			{
				if (value <= ValueMax)
				{
					value_alarm_min = value;
					Invalidate();
				}
			}
		}

		/// <summary>
		/// 获取或设置仪表盘的分割段数，最小为2，最大1000
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置仪表盘的分割段数，最小为2，最大1000")]
		[DefaultValue(10)]
		public int SegmentCount
		{
			get
			{
				return segment_count;
			}
			set
			{
				if (value > 1 && value < 1000)
				{
					segment_count = value;
					Invalidate();
				}
			}
		}

		/// <summary>
		/// 获取或设置仪表盘的单位描述文本
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置仪表盘的单位描述文本")]
		[DefaultValue("")]
		public string UnitText
		{
			get
			{
				return value_unit_text;
			}
			set
			{
				value_unit_text = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置文本是否是指针的下面
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置文本是否是指针的下面")]
		[DefaultValue(true)]
		public bool IsTextUnderPointer
		{
			get
			{
				return text_under_pointer;
			}
			set
			{
				text_under_pointer = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 通常情况，仪表盘不会大于半个圆，除非本属性设置为 True
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("通常情况，仪表盘不会大于半个圆，除非本属性设置为 True")]
		[DefaultValue(false)]
		public bool IsBigSemiCircle
		{
			get
			{
				return isBigSemiCircle;
			}
			set
			{
				isBigSemiCircle = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置控件的前景色
		/// </summary>
		[Category("HslControls")]
		[Description("获取或设置控件的前景色")]
		[DefaultValue(typeof(Color), "DodgerBlue")]
		public override Color ForeColor
		{
			get
			{
				return base.ForeColor;
			}
			set
			{
				base.ForeColor = value;
				foreBrush.Dispose();
				foreBrush = new SolidBrush(value);
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置报警区段的颜色
		/// </summary>
		[Category("HslControls")]
		[Description("获取或设置报警区段的颜色")]
		[DefaultValue(typeof(Color), "OrangeRed")]
		public Color GaugeAlarmColor
		{
			get
			{
				return color_gauge_alarm;
			}
			set
			{
				color_gauge_alarm = value;
				pen_gauge_alarm?.Dispose();
				pen_gauge_alarm = new Pen(color_gauge_alarm, 3f);
				pen_gauge_alarm.DashStyle = DashStyle.Custom;
				pen_gauge_alarm.DashPattern = new float[2]
				{
					5f,
					1f
				};
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置指针的大小值
		/// </summary>
		[Category("HslControls")]
		[Description("获取或设置指针的大小值")]
		[DefaultValue(5)]
		public int PointerSize
		{
			get
			{
				return pointerSize;
			}
			set
			{
				pointerSize = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置完全自定义的刻度表示数据
		/// </summary>
		[Category("HslControls")]
		[Description("获取或设置完全自定义的刻度表示数据")]
		[DefaultValue("")]
		public string CustomerCalibration
		{
			get
			{
				return customerCalibration;
			}
			set
			{
				customerCalibration = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 获取或设置单位文本信息是否显示在控件的下方
		/// </summary>
		[Browsable(true)]
		[Category("HslControls")]
		[Description("获取或设置单位文本信息是否显示在控件的下方")]
		[DefaultValue(false)]
		public bool IsTextInfoRenderBlow
		{
			get
			{
				return isTextInfoRenderBlow;
			}
			set
			{
				isTextInfoRenderBlow = value;
				Invalidate();
			}
		}

		/// <summary>
		/// 实例化一个仪表盘控件
		/// </summary>
		public HslGauge()
		{
			InitializeComponent();
			brush_gauge_pointer = new SolidBrush(color_gauge_pointer);
			sf = new StringFormat();
			sf.Alignment = StringAlignment.Center;
			sf.LineAlignment = StringAlignment.Center;
			pen_gauge_alarm = new Pen(color_gauge_alarm, 3f);
			pen_gauge_alarm.DashStyle = DashStyle.Custom;
			pen_gauge_alarm.DashPattern = new float[2]
			{
				5f,
				1f
			};
			hybirdLock = new object();
			m_UpdateAction = base.Invalidate;
			SetStyle(ControlStyles.UserPaint | ControlStyles.SupportsTransparentBackColor, value: true);
			SetStyle(ControlStyles.ResizeRedraw, value: true);
			SetStyle(ControlStyles.OptimizedDoubleBuffer, value: true);
			SetStyle(ControlStyles.AllPaintingInWmPaint, value: true);
			ForeColor = Color.DodgerBlue;
		}

		/// <summary>
		/// 重绘
		/// </summary>
		/// <param name="e">重绘的事件</param>
		protected override void OnPaint(PaintEventArgs e)
		{
			if (!Authorization.iashdiadasbdnajsdhjaf())
			{
				return;
			}
			float value_paint = this.value_paint;
			if (value_paint > ValueMax)
			{
				value_paint = ValueMax;
			}
			if (value_paint < ValueStart)
			{
				value_paint = ValueStart;
			}
			Graphics g = e.Graphics;
			g.SmoothingMode = SmoothingMode.HighQuality;
			g.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
			CenterPoint setting = GetCenterPoint();
			if (setting == null)
			{
				return;
			}
			Point center = setting.Point;
			int radius = setting.Radius;
			float angle = Convert.ToSingle(setting.Angle);
			Rectangle circular = new Rectangle(-radius, -radius, 2 * radius, 2 * radius);
			Rectangle circular_larger = new Rectangle(-radius - 5, -radius - 5, 2 * radius + 10, 2 * radius + 10);
			g.TranslateTransform(center.X, center.Y);
			g.RotateTransform(angle - 90f);
			int totle = segment_count;
			for (int i = 0; i <= totle; i++)
			{
				int markWidth = (radius > 200) ? 3 : 2;
				int markLength = (radius > 100) ? 12 : 8;
				g.FillPolygon(pen_gauge_mark, new PointF[6]
				{
					new PointF(-markWidth, -radius),
					new PointF(-markWidth, -radius + markLength),
					new PointF(0f, -radius + markLength + markLength / 2 - 1),
					new PointF(markWidth, -radius + markLength),
					new PointF(markWidth, -radius),
					new PointF(-markWidth, -radius)
				});
				for (int k = 0; k < 5; k++)
				{
					using Pen pen_gauge_border = new Pen(color_gauge_border, (base.Width > 300) ? 3 : 2);
					g.RotateTransform((180f - 2f * angle) / (float)totle / 5f);
					if (i != totle && k != 5)
					{
						g.DrawLine(pen_gauge_border, 0, -radius, 0, -radius + 6);
					}
				}
			}
			g.RotateTransform((0f - (180f - 2f * angle)) / (float)totle);
			g.RotateTransform(angle - 90f);
			string[] calibration = null;
			if (!string.IsNullOrEmpty(customerCalibration))
			{
				calibration = customerCalibration.Split(new char[1]
				{
					';'
				}, StringSplitOptions.RemoveEmptyEntries);
			}
			for (int j = 0; j <= totle; j++)
			{
				double current = ValueStart + (ValueMax - ValueStart) * (float)j / (float)totle;
				double angleMark = (double)(180f - angle) - (current - (double)ValueStart) / (double)(ValueMax - ValueStart) * (double)(180f - 2f * angle);
				PointF mark = new PointF((float)(radius - 12 - Font.Height) * (float)Math.Cos(angleMark * Math.PI / 180.0), (float)(-(radius - 12 - Font.Height)) * (float)Math.Sin(angleMark * Math.PI / 180.0));
				if (calibration != null && j < calibration.Length)
				{
					g.DrawString(calibration[j], Font, foreBrush, new RectangleF(mark.X - 100f, mark.Y - 40f, 200f, 80f), sf);
				}
				else
				{
					g.DrawString(current.ToString(), Font, foreBrush, new RectangleF(mark.X - 100f, mark.Y - 40f, 200f, 80f), sf);
				}
			}
			Rectangle text = new Rectangle(-200, -(radius * 3 / 5 - 3), 400, Font.Height + 3);
			if (isTextInfoRenderBlow)
			{
				text.Y = radius / 5 + 3;
			}
			if (IsTextUnderPointer)
			{
				if (base.Width > 200)
				{
					g.DrawString(Value.ToString(), Font, foreBrush, text, sf);
				}
				text.Offset(0, Font.Height);
				if (!string.IsNullOrEmpty(UnitText))
				{
					g.DrawString(UnitText, Font, foreBrush, text, sf);
				}
			}
			g.RotateTransform(angle - 90f);
			g.RotateTransform((value_paint - ValueStart) / (ValueMax - ValueStart) * (180f - 2f * angle));
			g.FillEllipse(rect: new Rectangle(-pointerSize, -pointerSize, pointerSize * 2, pointerSize * 2), brush: brush_gauge_pointer);
			Point[] points = new Point[5]
			{
				new Point(pointerSize, 0),
				new Point((pointerSize / 2 < 1) ? 1 : (pointerSize / 2), -radius + 20),
				new Point(0, -radius),
				new Point(-((pointerSize / 2 < 1) ? 1 : (pointerSize / 2)), -radius + 20),
				new Point(-pointerSize, 0)
			};
			g.FillPolygon(brush_gauge_pointer, points);
			g.RotateTransform((0f - (value_paint - ValueStart)) / (ValueMax - ValueStart) * (180f - 2f * angle));
			g.RotateTransform(90f - angle);
			if (value_alarm_min > ValueStart && value_alarm_min <= ValueMax)
			{
				g.DrawArc(pen_gauge_alarm, circular_larger, angle - 180f, (ValueAlarmMin - ValueStart) / (ValueMax - ValueStart) * (180f - 2f * angle));
			}
			if (value_alarm_max >= ValueStart && value_alarm_max < ValueMax)
			{
				float angle_max = (value_alarm_max - ValueStart) / (ValueMax - ValueStart) * (180f - 2f * angle);
				g.DrawArc(pen_gauge_alarm, circular_larger, -180f + angle + angle_max, 180f - 2f * angle - angle_max);
			}
			if (!IsTextUnderPointer)
			{
				if (base.Width > 200)
				{
					g.DrawString(Value.ToString(), Font, foreBrush, text, sf);
				}
				text.Offset(0, Font.Height);
				if (!string.IsNullOrEmpty(UnitText))
				{
					g.DrawString(UnitText, Font, foreBrush, text, sf);
				}
			}
			g.ResetTransform();
			base.OnPaint(e);
		}

		/// <summary>
		/// 获取中心点的坐标
		/// </summary>
		/// <returns>中心点对象</returns>
		private CenterPoint GetCenterPoint()
		{
			CenterPoint centerPoint = new CenterPoint();
			if (base.Height <= 35)
			{
				return null;
			}
			if (base.Width <= 20)
			{
				return null;
			}
			if (!IsBigSemiCircle)
			{
				centerPoint.Radius = base.Height - 30;
				if ((double)(base.Width - 40) / 2.0 > (double)centerPoint.Radius)
				{
					centerPoint.Angle = Math.Acos(1.0) * 180.0 / Math.PI;
				}
				else
				{
					centerPoint.Angle = Math.Acos((double)(base.Width - 40) / 2.0 / (double)(base.Height - 30)) * 180.0 / Math.PI;
				}
				centerPoint.Point = new Point(base.Width / 2, base.Height - 10);
				return centerPoint;
			}
			centerPoint.Radius = (base.Width - 40) / 2;
			if (base.Height - 30 < centerPoint.Radius)
			{
				centerPoint.Radius = base.Height - 30;
				centerPoint.Angle = Math.Acos(1.0) * 180.0 / Math.PI;
				centerPoint.Point = new Point(base.Width / 2, base.Height - 10);
				return centerPoint;
			}
			int left = base.Height - 30 - centerPoint.Radius;
			if (left > centerPoint.Radius)
			{
				left = centerPoint.Radius;
			}
			centerPoint.Angle = (0.0 - Math.Asin((double)left * 1.0 / (double)centerPoint.Radius)) * 180.0 / Math.PI;
			centerPoint.Point = new Point(base.Width / 2, centerPoint.Radius + 20);
			return centerPoint;
		}

		private void ThreadPoolUpdateProgress(object obj)
		{
			try
			{
				int version = (int)obj;
				if (value_paint == value_current)
				{
					return;
				}
				float m_speed = Math.Abs(value_paint - value_current) / 10f;
				if (m_speed == 0f)
				{
					m_speed = 1f;
				}
				while (value_paint != value_current)
				{
					Thread.Sleep(17);
					if (version != m_version)
					{
						break;
					}
					lock (hybirdLock)
					{
						float newActual = 0f;
						if (value_paint > value_current)
						{
							float offect2 = value_paint - value_current;
							if (offect2 > m_speed)
							{
								offect2 = m_speed;
							}
							newActual = value_paint - offect2;
						}
						else
						{
							float offect = value_current - value_paint;
							if (offect > m_speed)
							{
								offect = m_speed;
							}
							newActual = value_paint + offect;
						}
						value_paint = newActual;
					}
					if (version == m_version)
					{
						if (base.IsHandleCreated)
						{
							Invoke(m_UpdateAction);
						}
						continue;
					}
					break;
				}
			}
			catch (Exception)
			{
			}
		}

		/// <summary> 
		/// 清理所有正在使用的资源。
		/// </summary>
		/// <param name="disposing">如果应释放托管资源，为 true；否则为 false。</param>
		protected override void Dispose(bool disposing)
		{
			if (disposing && components != null)
			{
				components.Dispose();
			}
			base.Dispose(disposing);
		}

		/// <summary> 
		/// 设计器支持所需的方法 - 不要修改
		/// 使用代码编辑器修改此方法的内容。
		/// </summary>
		private void InitializeComponent()
		{
			SuspendLayout();
			base.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
			BackColor = System.Drawing.Color.Transparent;
			base.Name = "HslGauge";
			ResumeLayout(false);
		}
	}
}
